---
title: "Date Range Picker"
description: "DateRangePicker combines two DateInputs and a RangeCalendar popover to allow users to enter or select a date and time range."
---

import {dateRangePickerContent} from "@/content/components/date-range-picker";

# Date Range Picker

Date Range Picker combines two DateInputs and a RangeCalendar popover to allow users to enter or select a date and time range.

<ComponentLinks component="date-picker" />

---

<CarbonAd/>

## Installation

<PackageManagers
  showGlobalInstallWarning
  commands={{
    cli: "npx heroui-cli@latest add date-picker",
    npm: "npm install @heroui/date-picker",
    yarn: "yarn add @heroui/date-picker",
    pnpm: "pnpm add @heroui/date-picker",
    bun: "bun add @heroui/date-picker",
  }}
/>

## Import

<ImportTabs
  commands={{
    main: 'import {DateRangePicker} from "@heroui/react";',
    individual: 'import {DateRangePicker} from "@heroui/date-picker";',
  }}
/>

## Usage

<CodeDemo title="Usage" files={dateRangePickerContent.usage} />

### Disabled

<CodeDemo title="Disabled" files={dateRangePickerContent.disabled} />

### Read Only

<CodeDemo title="Read Only" files={dateRangePickerContent.readOnly} />

### Required

If you pass the `isRequired` property to the input, it will have a `danger` asterisk at
the end of the label and the input will be required.

<CodeDemo title="Required" files={dateRangePickerContent.required} />

### Variants

<CodeDemo title="Variants" files={dateRangePickerContent.variants} />

### Visible Months

By default, the calendar popover displays a single month. The `visibleMonths` prop allows displaying up to 3 months at a time, if screen space permits.

<CodeDemo title="Visible Months" files={dateRangePickerContent.visibleMonth} />

### Custom first day of week

By default, the first day of the week is automatically set based on the current locale. This can be changed by setting the `firstDayOfWeek` prop to `'sun'`, `'mon'`, `'tue'`, `'wed'`, `'thu'`, `'fri'`, or `'sat'`.

<CodeDemo title="Custom first day of week" files={dateRangePickerContent.firstDayOfWeek} />

### Page Behavior

By default, when pressing the next or previous buttons, pagination will advance by the `visibleMonths` value. This behavior can be changed to page by single months instead, by setting `pageBehavior` to `single`.

<CodeDemo title="Page Behavior" files={dateRangePickerContent.pageBehavior} />

### Label Placements

You can change the position of the label by setting the `labelPlacement` property to `inside`, `outside` or `outside-left`.

<CodeDemo title="Label Placements" files={dateRangePickerContent.labelPlacements} />

> **Note**: If the `label` is not passed, the `labelPlacement` property will be `outside` by default.

### With Description

You can add a description to the input by passing the `description` property.

<CodeDemo title="With Description" files={dateRangePickerContent.description} />

### With Error Message

You can combine the `isInvalid` and `errorMessage` properties to show an invalid input.

<CodeDemo title="With Error Message" files={dateRangePickerContent.errorMessage} />

You can also pass an error message as a function. This allows for dynamic error message handling based on the [ValidationResult](https://github.com/adobe/react-spectrum/blob/1cacbf1d438675feb3859fee54b17e620b458d9c/packages/%40react-types/shared/src/inputs.d.ts#L44-L51).

<CodeDemo title="With Error Message Function" files={dateRangePickerContent.errorMessageFunction} />

### With Month and Year Pickers

You can show month and year pickers in the calendar popover by setting the `showMonthAndYearPickers` property to `true`. However, passing a number greater than 1 to the `visibleMonths` prop will disable this feature.

<CodeDemo title="With Month and Year Pickers" files={dateRangePickerContent.withMonthAndYearPickers} />

### With Time Fields

DateRangePicker automatically includes time fields when a `CalendarDateTime` or `ZonedDateTime` object is provided as the value.

<CodeDemo title="With Time Fields" files={dateRangePickerContent.withTimeField} />

### Selector Icon

You can use the `selectorIcon` to add content to the start and end of the date-range-picker.

<CodeDemo title="Selector Icon" files={dateRangePickerContent.selectorIcon} />

### Selector Button Placement

You can change the position of the selector button by setting the `selectorButtonPlacement` property to `start` or `end`.

<CodeDemo title="Selector Button Placement" files={dateRangePickerContent.selectorButtonPlacement} />

### Controlled

You can use the `value` and `onChange` properties to control the input value.

<CodeDemo title="Controlled" files={dateRangePickerContent.controlled} />

### Time Zones

DateRangePicker is time zone aware when a `ZonedDateTime` object is provided as the value. In this case, the time zone abbreviation is displayed,
and time zone concerns such as daylight saving time are taken into account when the value is manipulated.

[@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) includes functions for parsing strings
in multiple formats into `ZonedDateTime` objects.

<PackageManagers
  commands={{
    npm: "npm install @internationalized/date@3.10.0",
    yarn: "yarn add @internationalized/date@3.10.0",
    pnpm: "pnpm add @internationalized/date@3.10.0",
  }}
/>

```jsx
import {parseZonedDateTime} from "@internationalized/date";
```

<Spacer y={2} />

<CodeDemo title="Time Zones" files={dateRangePickerContent.timeZones} />

### Granularity

The granularity prop allows you to control the smallest unit that is displayed by DateRangePicker By default,
the value is displayed with "day" granularity (year, month, and day),
and `CalendarDateTime` and `ZonedDateTime` values are displayed with "minute" granularity.

[@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) includes functions for parsing strings
in multiple formats into `ZonedDateTime` objects.

<PackageManagers
  commands={{
    npm: "npm install @internationalized/date@3.10.0 @react-aria/i18n@3.12.13",
    yarn: "yarn add @internationalized/date@3.10.0 @react-aria/i18n@3.12.13",
    pnpm: "pnpm add @internationalized/date@3.10.0 @react-aria/i18n@3.12.13",
  }}
/>

```jsx
import {DateValue, now, parseAbsoluteToLocal} from "@internationalized/date";
import {useDateFormatter} from "@react-aria/i18n";
```

<Spacer y={2} />

<CodeDemo title="Time Zones" files={dateRangePickerContent.granularity} />

### Min Date And Max Date

The minValue and maxValue props can also be used to ensure the value is within a specific range.

[@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) includes functions for parsing strings
in multiple formats into `ZonedDateTime` objects.

<PackageManagers
  commands={{
    npm: "npm install @internationalized/date@3.10.0",
    yarn: "yarn add @internationalized/date@3.10.0",
    pnpm: "pnpm add @internationalized/date@3.10.0",
  }}
/>

```jsx
import {getLocalTimeZone, parseDate, today} from "@internationalized/date";
```

<CodeDemo title="Min Date And Max Date" files={dateRangePickerContent.minAndMaxDate} />

### International Calendar

DateRangePicker supports selecting dates in many calendar systems used around the world, including Gregorian, Hebrew, Indian, Islamic, Buddhist, and more.
Dates are automatically displayed in the appropriate calendar system for the user's locale.
The calendar system can be overridden using the [Unicode calendar locale extension](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/calendar#adding_a_calendar_in_the_locale_string),
passed to the [I18nProvider](https://react-spectrum.adobe.com/react-aria/I18nProvider.html) component.

[@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) includes functions for parsing strings
in multiple formats into `ZonedDateTime` objects.

<PackageManagers
  commands={{
    npm: "npm install @internationalized/date@3.10.0 @react-aria/i18n@3.12.13",
    yarn: "yarn add @internationalized/date@3.10.0 @react-aria/i18n@3.12.13",
    pnpm: "pnpm add @internationalized/date@3.10.0 @react-aria/i18n@3.12.13",
  }}
/>

```jsx
import {DateValue, now, parseAbsoluteToLocal} from "@internationalized/date";
import {I18nProvider} from "@react-aria/i18n";
```

<CodeDemo title="International Calendar" files={dateRangePickerContent.internationalCalendar} />

### Unavailable Dates

DateRangePicker supports marking certain dates as unavailable. These dates cannot be selected by the user and are displayed with a crossed out appearance in the calendar. In the date field, an invalid state is displayed if a user enters an unavailable date.

[@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) includes functions for parsing strings
in multiple formats into `ZonedDateTime` objects.

<PackageManagers
  commands={{
    npm: "npm install @internationalized/date@3.10.0 @react-aria/i18n@3.12.13",
    yarn: "yarn add @internationalized/date@3.10.0 @react-aria/i18n@3.12.13",
    pnpm: "pnpm add @internationalized/date@3.10.0 @react-aria/i18n@3.12.13",
  }}
/>

```jsx
import {today, isWeekend, getLocalTimeZone} from "@internationalized/date";
import {useLocale} from "@react-aria/i18n";
```

<CodeDemo title="Unavailable Dates" files={dateRangePickerContent.unavailableDates} />

### Non Contiguous

The allowsNonContiguousRanges prop enables a range to be selected even if there are unavailable dates in the middle.
The value emitted in the onChange event will still be a single range with a start and end property,
but unavailable dates will not be displayed as selected.
It is up to applications to split the full selected range into multiple as needed for business logic.

[@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) includes functions for parsing strings
in multiple formats into `ZonedDateTime` objects.

<PackageManagers
  commands={{
    npm: "npm install @internationalized/date@3.10.0 @react-aria/i18n@3.12.13",
    yarn: "yarn add @internationalized/date@3.10.0 @react-aria/i18n@3.12.13",
    pnpm: "pnpm add @internationalized/date@3.10.0 @react-aria/i18n@3.12.13",
  }}
/>

```jsx
import {today, isWeekend, getLocalTimeZone} from "@internationalized/date";
import {useLocale} from "@react-aria/i18n";
```

<CodeDemo title="Non Contiguous" files={dateRangePickerContent.nonContigous} />

### Presets

[@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) includes functions for parsing strings
in multiple formats into `ZonedDateTime` objects.

<PackageManagers
  commands={{
    npm: "npm install @internationalized/date@3.10.0 @react-aria/i18n@3.12.13",
    yarn: "yarn add @internationalized/date@3.10.0 @react-aria/i18n@3.12.13",
    pnpm: "pnpm add @internationalized/date@3.10.0 @react-aria/i18n@3.12.13",
  }}
/>

```jsx
import {
  DateValue,
  now,
  startOfWeek,
  startOfMonth,
  getLocalTimeZone,
} from "@internationalized/date";
import {useLocale, useDateFormatter} from "@react-aria/i18n";
```

<CodeDemo title="Presets" files={dateRangePickerContent.presets} />

## Slots

- **base**: base element. it handles alignment, placement, and general appearance.
- **label**: Label of the date-range-picker, it is the one that is displayed above, inside or left of the date-input.
- **calendar**: The calendar element.
- **selectorButton**: Selector button element.
- **selectorIcon**: Selector icon element.
- **popoverContent**: The calendar popover element.
- **calendarContent**: The calendar's content element.
- **inputWrapper**: Wraps the `label` (when it is inside) and the `innerWrapper`.
- **input**: The input element.
- **segment**: The segment element.
- **separator**: The separator element.
- **bottomContent**: The bottom content element.
- **timeInputWrapper**: The wrapper element for the input element.
- **helperWrapper**: Wraps the `description` and the `errorMessage`.
- **description**: The description of the date-input.
- **errorMessage**: The error message of the date-input.

### Custom Styles

You can customize the `DateRangePicker` component by passing custom Tailwind CSS classes to the component slots.

<CodeDemo title="Custom Styles" files={dateRangePickerContent.customStyles} />

<Spacer y={4} />

## Data Attributes

`DateRangePicker` has the following attributes on the `base` element:

- **data-slot**:
  All slots have this prop. which slot the element represents(e.g. `canlendar`).
- **data-open**:
  Indicates if the calendar popover is open.
- **data-invalid**:
  When the date-range-picker is invalid. Based on `isInvalid` prop.
- **data-required**:
  When the date-range-picker is required. Based on `isRequired` prop.
- **data-readonly**:
  When the date-range-picker is readonly. Based on `isReadOnly` prop.
- **data-disabled**:
  When the date-range-picker is disabled. Based on `isDisabled` prop.
- **data-has-start-content**:
  When the date-range-picker has a start content. Base on those `startContent` prop.
- **data-has-end-content**:
  When the date-range-picker has a end content. Base on those `endContent` prop.
- **data-has-multiple-months**:
  When the date-range-picker's `visibleMonth` is more than 2.

<Spacer y={4} />

## Accessibility

- Each date and time unit is displayed as an individually focusable and editable segment, which allows users an easy way to edit dates using the keyboard, in any date format and locale
- Users can also open a calendar popover to select date ranges in a standard month grid. Localized screen reader messages are included to announce when the selection and visible date range change.
- Date segments are editable using an easy to use numeric keypad, date ranges can be selected by dragging over dates in the calendar using a touch screen, and all interactions are accessible using touch-based screen readers.
- Integrates with HTML forms, supporting required, minimum and maximum values, unavailable dates, custom validation functions, realtime validation, and server-side validation errors

<Spacer y={4} />

## API

### DateRangePicker Props

<APITable
  data={[
    {
      attribute: "label",
      type: "ReactNode",
      description: "The content to display as the label.",
      default: "-"
    },
    {
      attribute: "value",
      type: "RangeValue<CalendarDate | CalendarDateTime | ZonedDateTime> | undefined | null",
      description: "The current value of the date-range-picker (controlled).",
      default: "-"
    },
    {
      attribute: "variant",
      type: "flat | bordered | faded | underlined",
      description: "The variant of the date input.",
      default: "flat"
    },
    {
      attribute: "color",
      type: "default | primary | secondary | success | warning | danger",
      description: "The color of the date input.",
      default: "default"
    },
    {
      attribute: "size",
      type: "sm | md | lg",
      description: "The size of the date input.",
      default: "md"
    },
    {
      attribute: "radius",
      type: "none | sm | md | lg | full",
      description: "The radius of the date input.",
      default: "-"
    },
    {
      attribute: "minValue",
      type: "RangeValue<CalendarDate | CalendarDateTime | ZonedDateTime> | undefined | null",
      description: "The minimum value of the date-range-picker.",
      default: "-"
    },
    {
      attribute: "maxValue",
      type: "RangeValue<CalendarDate | CalendarDateTime | ZonedDateTime> | undefined | null",
      description: "The maximum value of the date-range-picker.",
      default: "-"
    },
    {
      attribute: "defaultValue",
      type: "string",
      description: "The default value of the date-range-picker (uncontrolled).",
      default: "-"
    },
    {
      attribute: "placeholderValue",
      type: "ZonedDateTime | CalendarDate | CalendarDateTime | undefined | null",
      description: "The placeholder of the date-range-picker.",
      default: "-"
    },
    {
      attribute: "description",
      type: "ReactNode",
      description: "A description for the date-range-picker. Provides a hint such as specific requirements for what to choose.",
      default: "-"
    },
    {
      attribute: "errorMessage",
      type: "ReactNode | (v: ValidationResult) => ReactNode",
      description: "An error message for the date input.",
      default: "-"
    },
    {
      attribute: "validate",
      type: "(value: RangeValue<MappedDateValue<DateValue>>) => ValidationError | true | null | undefined",
      description: "Validate input values when committing (e.g. on blur), returning error messages for invalid values.",
      default: "-"
    },
    {
      attribute: "validationBehavior",
      type: "native | aria",
      description: "Whether to use native HTML form validation or ARIA validation. When wrapped in a Form component, the default is `aria`. Otherwise, the default is `native`.",
      default: "native"
    },
    {
      attribute: "startContent",
      type: "ReactNode",
      description: "Element to be rendered in the left side of the date-range-picker.",
      default: "-"
    },
    {
      attribute: "endContent",
      type: "ReactNode",
      description: "Element to be rendered in the right side of the date-range-picker.",
      default: "-"
    },
    {
      attribute: "startName",
      type: "string",
      description: "The name of the start date input element, used when submitting an HTML form.",
      default: "-"
    },
    {
      attribute: "endName",
      type: "string",
      description: "The name of the end date input element, used when submitting an HTML form.",
      default: "-"
    },
    {
      attribute: "labelPlacement",
      type: "inside | outside | outside-left",
      description: "The position of the label.",
      default: "inside"
    },
    {
      attribute: "isOpen",
      type: "boolean",
      description: "Whether the date picker popover is open.",
      default: "-"
    },
    {
      attribute: "defaultOpen",
      type: "boolean",
      description: "Whether the date picker popover is open by default.",
      default: "false"
    },
    {
      attribute: "isRequired",
      type: "boolean",
      description: "Whether user input is required on the date-range-picker before form submission.",
      default: "false"
    },
    {
      attribute: "isReadOnly",
      type: "boolean",
      description: "Whether the date-range-picker can be selected but not changed by the user.",
      default: "false"
    },
    {
      attribute: "isDisabled",
      type: "boolean",
      description: "Whether the date-range-picker is disabled.",
      default: "false"
    },
    {
      attribute: "isInvalid",
      type: "boolean",
      description: "Whether the date-range-picker is invalid.",
      default: "false"
    },
    {
      attribute: "selectorIcon",
      type: "ReactNode",
      description: "The icon to toggle the date picker popover. Usually a calendar icon.",
      default: "-"
    },
    {
      attribute: "pageBehavior",
      type: "single | visible",
      description: "Controls the behavior of paging.",
      default: "visible"
    },
    {
      attribute: "visibleMonths",
      type: "number",
      description: "The number of months to display at once. Up to 3 months are supported.",
      default: "1"
    },
    {
      attribute: "firstDayOfWeek",
      type: "sun | mon | tue | wed | thu | fri | sat",
      description: "The day that starts the week.",
      default: "-"
    },
    {
      attribute: "selectionAlignment",
      type: "start | center | end",
      description: "Determines the alignment of the visible months on initial render based on the current selection or current date if there is no selection.",
      default: "center"
    },
    {
      attribute: "autoFocus",
      type: "boolean",
      description: "Whether the element should receive focus on render.",
      default: "false"
    },
    {
      attribute: "hourCycle",
      type: "12 | 24",
      description: "Whether to display the time in 12 or 24 hour format.",
      default: "-"
    },
    {
      attribute: "granularity",
      type: "day | hour | minute | second",
      description: "Determines the smallest unit that is displayed in the date picker.",
      default: "-"
    },
    {
      attribute: "hideTimeZone",
      type: "boolean",
      description: "Whether to hide the time zone abbreviation.",
      default: "false"
    },
    {
      attribute: "allowsNonContiguousRanges",
      type: "boolean",
      description: "When combined with isDateUnavailable, determines whether non-contiguous ranges may be selected.",
      default: "false"
    },
    {
      attribute: "shouldForceLeadingZeros",
      type: "boolean",
      description: "Whether to always show leading zeros in the month, day, and hour fields.",
      default: "true"
    },
    {
      attribute: "calendarWidth",
      type: "number",
      description: "The width to be applied to the calendar component.",
      default: "256"
    },
    {
      attribute: "CalendarTopContent",
      type: "ReactNode",
      description: "Top content to be rendered in the calendar component.",
      default: "-"
    },
    {
      attribute: "CalendarBottomContent",
      type: "ReactNode",
      description: "Bottom content to be rendered in the calendar component.",
      default: "-"
    },
    {
      attribute: "showMonthAndYearPickers",
      type: "boolean",
      description: "Whether the calendar should show month and year pickers.",
      default: "false"
    },
    {
      attribute: "popoverProps",
      type: "PopoverProps",
      description: "Props to be passed to the popover component.",
      default: "{ placement: \"bottom\", triggerScaleOnOpen: false, offset: 13 }"
    },
    {
      attribute: "selectorButtonProps",
      type: "ButtonProps",
      description: "Props to be passed to the selector button component.",
      default: "{ size: \"sm\", variant: \"light\", radius: \"full\", isIconOnly: true }"
    },
    {
      attribute: "selectorButtonPlacement",
      type: "start | end",
      description: "The position of the selector button.",
      default: "end"
    },
    {
      attribute: "calendarProps",
      type: "CalendarProps",
      description: "Props to be passed to the calendar component.",
      default: "-"
    },
    {
      attribute: "timeInputProps",
      type: "TimeInputProps",
      description: "Props to be passed to the time input component.",
      default: "-"
    },
    {
      attribute: "disableAnimation",
      type: "boolean",
      description: "Whether to disable all animations in the date picker.",
      default: "false"
    },
    {
      attribute: "classNames",
      type: "Partial<Record<\"base\" | \"label\" | \"calendar\" | \"selectorButton\" | \"selectorIcon\" | \"popoverContent\" | \"calendarContent\" | \"inputWrapper\" | \"input\" | \"segment\" | \"separator\" | \"bottomContent\" | \"timeInputWrapper\" | \"timeInputLabel\" | \"timeInput\" | \"helperWrapper\" | \"description\" | \"errorMessage\", string>>",
      description: "Allows to set custom class names for the date-range-picker slots. You can also pass Date Input classNames here.",
      default: "-"
    }
  ]}
/>

### DateRangePicker Events

<APITable
  data={[
    {
      attribute: "onChange",
      type: "(value: RangeValue<CalendarDate | CalendarDateTime | ZonedDateTime>) => void",
      description: "Handler that is called when the date-range-picker's value changes.",
      default: "-"
    },
    {
      attribute: "onOpenChange",
      type: "(isOpen: boolean) => void",
      description: "Handler that is called when the date picker popover is opened or closed.",
      default: "-"
    },
    {
      attribute: "onFocus",
      type: "(e: FocusEvent<HTMLInputElement>) => void",
      description: "Handler that is called when the element receives focus.",
      default: "-"
    },
    {
      attribute: "onBlur",
      type: "(e: FocusEvent<HTMLInputElement>) => void",
      description: "Handler that is called when the element loses focus.",
      default: "-"
    },
    {
      attribute: "onFocusChange",
      type: "(isFocused: boolean) => void",
      description: "Handler that is called when the element's focus status changes.",
      default: "-"
    },
    {
      attribute: "onKeyDown",
      type: "(e: KeyboardEvent) => void",
      description: "Handler that is called when a key is pressed.",
      default: "-"
    },
    {
      attribute: "onKeyUp",
      type: "(e: KeyboardEvent) => void",
      description: "Handler that is called when a key is released.",
      default: "-"
    }
  ]}
/>
